#ifndef SEARCHABLEQUEUE_H
#define SEARCHABLEQUEUE_H
#include <map>
#include <queue>

#include <cstddef>

#include <semaphore.h>

template <typename T1, typename T2>
class SearchableQueue
{
public:
    SearchableQueue(unsigned int size = 10)
    {
        sem_init(&this->m_mutex, 0, 1);
        this->m_size = size;
    }

    void enqueue(T1 key, T2 value){
        sem_wait(&this->m_mutex);
        this->m_queue.push(key);
        this->m_data[key] = value;
        while(this->m_queue.size() > this->m_size){
            T1 key = this->m_queue.front();
            this->m_data.erase(key);
            this->m_queue.pop();
        }
        sem_post(&this->m_mutex);
    }

    T2 dequeue(T1 *key = NULL){
        sem_wait(&this->m_mutex);
        if(key != NULL){
            *key = this->m_queue.front();
        }
        T1 _key = this->m_queue.front();
        this->m_queue.pop();
        T2 value = this->m_data[_key];
        this->m_data.erase(_key);
        sem_post(&this->m_mutex);
        return value;
    }

    bool find(T1 key, T2 *result = NULL){
        sem_wait(&this->m_mutex);
        if(this->m_data.find(key) != this->m_data.end()){
            if(result != NULL){
                *result = this->m_data[key];
            }
            sem_post(&this->m_mutex);
            return true;
        }else{
            sem_post(&this->m_mutex);
            return false;
        }

    }

    void setSize(unsigned int size){
        sem_wait(&this->m_mutex);
        this->m_size = size;
        sem_post(&this->m_mutex);
    }

private:
    std::map<T1, T2> m_data;
    std::queue<T1> m_queue;
    unsigned int m_size;
    sem_t m_mutex;
};




#endif // SEARCHABLEQUEUE_H
